package com.love.poetry.interfaces;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;

import java.util.List;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.love.poetry.application.security.RoleService;
import com.love.poetry.application.security.UserService;
import com.love.poetry.domain.security.Role;
import com.love.poetry.domain.security.User;
import com.love.poetry.infrastructure.exception.UserExistsException;
import com.love.poetry.infrastructure.exception.UserNotAuthorityException;
import com.love.poetry.infrastructure.util.JsonMessage;
import com.love.poetry.infrastructure.util.MD5HashUtils;
import com.youboy.core.web.AjaxUtils;
import com.youboy.core.web.controller.ControllerSupport;
import com.youboy.util.AssertUtils;

@Controller
public class AdminController extends ControllerSupport{

	public static final int UNKNOWN_ACCOUT_ERROR_CODE = 1;
	public static final int LOCKED_ACCOUT_ERROR_CODE = 2;
	public static final int AUTHENTICATION_ERROR_CODE = 4;
	public static final int OTHER_ERROR_CODE = 16;
	public static final int USERNOTAUTHORITY_ERROR_CODE = 18;

	@Autowired
	private UserService userService;
	@Autowired
	private RoleService roleService;

	/**
	 * not the login submit request,just return to login page.
	 * 
	 * @return
	 */
	@RequestMapping(value = "/login", method = GET)
	public String login() {
		return "admin/login";
	}

	/**
	 * login submit request
	 * 
	 * @return
	 */
	@RequestMapping(value = "/login", method = POST)
	public String login(HttpServletRequest request) {
		try {
			checkUserAuthority(request);

			Subject subject = SecurityUtils.getSubject();

			// if it has authenticated,logout first
			if (subject.isAuthenticated()) {
				subject.logout();
			}

			// checkCaptcha(request, session);
			AuthenticationToken token = createToken(request);

			subject.login(token);
		} catch (Exception e) {
			return "redirect:/login?code=" + translateException(e);
		}

		return "redirect:/admin/dashboard/";
	}

	private void checkUserAuthority(HttpServletRequest request) {
		String username = WebUtils.getCleanParam(request, "username");
		userService.checkUserAuthority(username);
	}

	private AuthenticationToken createToken(HttpServletRequest request) {
		String username = WebUtils.getCleanParam(request, "username");
		String password = WebUtils.getCleanParam(request, "password");

		String passwordAsMd5 = MD5HashUtils.asMD5(password, username);
		String rememberMeAsString = WebUtils.getCleanParam(request,"rememberMe");

		boolean rememberMe = false;
		if (null != rememberMeAsString) {
			rememberMe = Boolean.valueOf(rememberMeAsString);
		}
		String host = request.getRemoteHost();
		return new UsernamePasswordToken(username, passwordAsMd5, rememberMe,host);
	}

	private int translateException(Exception e) {

		if (e instanceof UserNotAuthorityException) {
			return USERNOTAUTHORITY_ERROR_CODE;
		}

		if (e instanceof UnknownAccountException) {
			return UNKNOWN_ACCOUT_ERROR_CODE;
		}

		if (e instanceof LockedAccountException) {
			return LOCKED_ACCOUT_ERROR_CODE;
		}

		if (e instanceof AuthenticationException) {
			return AUTHENTICATION_ERROR_CODE;
		}

		return OTHER_ERROR_CODE;
	}

	@RequestMapping(value = "/admin/logout/", method = { GET, POST })
	public String logout() {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
		return "redirect:/login/";
	}

	@RequestMapping(value = "/admin/header/", method = GET)
	public String header() {
		return "admin/header";
	}

	@RequestMapping(value = "/admin/footer/", method = GET)
	public String footer() {
		return "admin/footer";
	}

	@RequestMapping(value = "/admin/dashboard/", method = GET)
	public String dashboard() {
		return "admin/dashboard";
	}

	@RequestMapping(value = "/admin/app-info/", method = GET)
	public String appInfo(Model model) {
		Properties props = System.getProperties();
		model.addAttribute("props", props);
		return "admin/app-info";
	}

	@RequestMapping(value = "/admin/data/", method = GET)
	public String data() {
		return "admin/data";
	}
	
	@RequestMapping(value={"/admin/{id}/modifymyself"},method=GET)
	public String modifyUserMyself(@PathVariable("id") String id, Model model) {
			User entity = userService.lazyGet(id);
			List<Role> roles = roleService.query(new Object());
			model.addAttribute(entity.ofRoles()).addAttribute("roles", roles).addAttribute("_method", "PUT");
			return "/security/user/myself_form";
	}
	@RequestMapping(value = "/admin/{id}/modifymyself", method = PUT)
	public String edit(@PathVariable("id") String id, HttpServletRequest request) {
		try {
			User entity = userService.lazyGet(id);
			
			String oldPassword=entity.getPassword(),newPassword=request.getParameter("password");		
			
			String oldUsername = entity.getUsername();
			bind(request, entity);
			boolean usernameNotModify = StringUtils.equals(oldUsername,entity.getUsername());
			AssertUtils.isTrue(usernameNotModify,new UnsupportedOperationException("Username can't modify!"));	
			entity.modify();
			if(StringUtils.equals(newPassword, oldPassword)){
				userService.update(entity.setPassword(oldPassword));
			}
			success("用户修改成功");
		} catch (Exception e) {
			return null;
		}
		return "redirect:/admin/"+id+"/modifymyself";
	}
	
	@RequestMapping(value = { "/checkRegistUser" }, method = POST)
	@ResponseBody
	public JsonMessage checkRegistUser(
			HttpServletRequest request,
			HttpSession session,
			@RequestHeader(value = "X-Requested-With", required = false) String requestWith) {
		try {
			if (!AjaxUtils.isAjaxRequest(requestWith)) {
				return JsonMessage.one().error()
						.message("Not supported operation!");
			}

			checkRegistUser(request);

		} catch (Exception e) {
			return userRegisterException(e);
		}
		return JsonMessage.one().success();
	}

	private void checkRegistUser(HttpServletRequest request) {
		String username = WebUtils.getCleanParam(request, "username");
		userService.checkRegisterUserName(username);
	}
	 private JsonMessage userRegisterException(Exception e) {
         
         if (e instanceof UserExistsException) {
                     return JsonMessage.one().userExist();
        }        
         return JsonMessage.one().error();
} 
}